
import java.io.*;
import java.net.*;
import java.util.*;

public class MultiServer extends Thread 
{
    public static int PORT_NUMBER = 5555;
    protected ServerSocket listen;
    int thread_count = 0;
    int count = 0;
    int GridSize;
    static boolean is_time_out_set = false;
    static long start_time, current_time, elapsed;
    
    public MultiServer(int gs)
    {
    	try
    	{
    		listen = new ServerSocket(PORT_NUMBER);
    		GridSize = gs;
    	}
    	catch (IOException io)
    	{
    		System.out.println("Exception in MultiServer ctor" + io.getMessage());
    	}
    	this.start();
    }
	
    public void run()
    {
    	
    	try
    	{
    		System.out.println("Creating and initializing static Maze objs");
    		new MazeServer(GridSize, GridSize);
    		while(thread_count < 1)
    		{
    			System.out.println("Waiting for the first connection....");
    			Socket cl = listen.accept();
    			start_time = System.currentTimeMillis();
    			current_time = System.currentTimeMillis();
    			elapsed = current_time - start_time;
    			thread_count++;
    			new Connects(cl, thread_count, (10000-elapsed));
    		}
    		
    		System.out.println("First player joined, accepting connections for 10secs more...");
   			
    		if(!is_time_out_set)
    		{
    		    listen.setSoTimeout(10000); // wait for 10s to accept connections
    		    is_time_out_set = true;
    		}
    		while(true)
    		{
    			try 
    		    {
    				Socket cl = listen.accept();
		 	        thread_count++;
		 	        current_time = System.currentTimeMillis();
		 	        elapsed = current_time - start_time;
			        new Connects(cl, thread_count, (10000-elapsed));
    		    }
    		    catch ( java.io.InterruptedIOException e ) 
    		    {
    			    //System.out.println("Time out, no more connections allowed....");
    			    break;
    		    }
    		}
    		/*while(true)
    		{
    			Socket cl = listen.accept();
    			count++;
    			new Connects(cl, count);
    		}*/
    	}
    	catch (IOException io)
    	{
    		System.out.println("Exception in run()" + io.getMessage());
    	}
    	
    }
	public static void main(String[] args) 
	{
		if(args.length < 1)
		{
			
			System.out.println("Usage: java MultiServer <GridSize>");
			System.exit(0);
		}
		int grid_size = Integer.parseInt(args[0]);
		new MultiServer(grid_size);
	}

}

class Connects extends Thread
{
	Socket cl;
	int thread_id;
	BufferedReader input_stream;
	PrintStream output_stream;
	ObjectInputStream serialize_in = null;
	ObjectOutputStream serialize_out = null;
    static int count;
    long time_to_wait;
	int x;

	public Connects(Socket s, int id, long wait_time)
	{
		cl = s;
		thread_id = id;
		time_to_wait = wait_time;
		try
		{
			input_stream = new BufferedReader(new InputStreamReader(cl.getInputStream()));
			output_stream = new PrintStream(cl.getOutputStream());
		    serialize_out = new ObjectOutputStream(cl.getOutputStream());
		}
		catch (IOException io)
		{

	        System.out.println("IOException ");
			return;
		}
		
    	this.start();
	System.out.println("Thread " + thread_id + " started");
	}
	
	public void run() throws IllegalThreadStateException
	{
		try
		{
			System.out.println("Waiting for " + time_to_wait);
			output_stream.println(time_to_wait);
		//Thread.sleep(time_to_wait);
		}
		catch(Exception e)
		{
			
		}
		System.out.println("Creating Maze obj for new client");
		
		MazeServer ms = new MazeServer(thread_id);
		LinkedList<Treasure> treasure_list;

		String input_direction;
		while(ms.GetNumTreasuresFound() < ms.GetTotalNumTreasures())
		{
		    try
		    {
		    	System.out.println("Waiting for input");
			    input_direction = input_stream.readLine();
			    ms.UpdatePosition(thread_id, input_direction);
			    
			    serialize_out.writeInt(thread_id);
			    serialize_out.writeInt(ms.GetXpos());
   			    serialize_out.writeInt(ms.GetYpos());
  			    serialize_out.writeInt(ms.GetTotalNumTreasures() - ms.GetNumTreasuresFound());
   			    serialize_out.writeInt(ms.GetIndividualTreasuresFound());
   			    
   			    serialize_out.writeObject(ms.GetPrivateList());
   			    serialize_out.writeObject(ms.GetPrivateMap());
   			    serialize_out.flush();
   			    serialize_out.reset();
   			    /*Iterator iterator = ms.GetPrivateMap().keySet().iterator();
				while( iterator. hasNext() )
				{
					String str = (String)iterator.next();
					int[] a = ms.GetPrivateMap().get(str);
					
					System.out.println("Player " + str + " is at " + "(" + a[0] + " , " + a[1] + ")");
				}*/
		    }
		
		    catch (IllegalThreadStateException ee)
			{
				System.out.println("Thread killed" + ee.getMessage());
			}
		    
		    catch (Exception ee)
		    {
			    System.out.println("SERVER::Exception(), thread_id = " + thread_id + " killed");
			    ms.CleanUp(thread_id);
			    break;
		    }
		}
		try
		{
			if(ms.GetNumTreasuresFound() == ms.GetTotalNumTreasures())
			{
			    System.out.println("ALL TREASURES FOUND...BYE");
			    System.exit(0);
			}
		}
		catch (Exception ee)
		{
			System.out.println("Thread killed" + ee.getMessage());
			System.exit(0);
		}
	}
}
